﻿using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Inovout.Web.Mvc;

namespace System.Web.Mvc
{
    public class WidgetDataDictionary : ViewDataDictionary
    {
        public WidgetDataDictionary(ViewDataDictionary viewData, Type modelDeclaringType)
            : this(viewData.Model, viewData, modelDeclaringType)
        { }
        public WidgetDataDictionary(object model, ViewDataDictionary viewData)
            : this(model, viewData, model.GetType())
        { }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="viewData"></param>
        /// <param name="modelDeclaringType"></param>
        /// <remarks>
        /// 会重新按modelDeclaringType创建ModelMetadata,故不能使用原先的Html.ViewData;
        /// </remarks>
        public WidgetDataDictionary(object model, ViewDataDictionary viewData, Type modelDeclaringType)
            : base(model)
        {
            this.ModelDeclaringType = modelDeclaringType;
            SetOriginalViewData(viewData);

            //利用CacheMetaDdat的机制，先行设置声明类型，不然之后将无法设置。
            if (model == null)
            {
                base.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, (Type)viewData["ModelType"] ?? modelDeclaringType);
            }
            WidgetModelMetadata.ModelDeclaringType = modelDeclaringType;
        }
        public WidgetDataDictionary(ViewDataDictionary viewData, WidgetModelMetadata metadata)
            : this(metadata.Model, viewData, metadata)
        {
        }
        public WidgetDataDictionary(object model, ViewDataDictionary viewData, WidgetModelMetadata metadata)
            : base(model)
        {
            ModelMetadata = metadata;
            this.ModelDeclaringType = ModelMetadata.ModelType;
            SetOriginalViewData(viewData);
        }
        public Type ModelDeclaringType { get; private set; }
        private void SetOriginalViewData(ViewDataDictionary viewData)
        {
            //不能是引用关系，因为会被外部修改其内部数据。
            this.OriginalViewData = new ViewDataDictionary(viewData);

            //复制DataSource
            foreach (var kv in this.OriginalViewData.Where(kv => kv.Key.StartsWith(ViewDataDictionaryExtensions.AdditionalViewDataKeyPrefix)))
            {
                this.Add(kv);
            }
            WidgetModelMetadata.Merge(viewData.ModelMetadata.AsWidgetModelMetadata());
        }
        internal ViewDataDictionary OriginalViewData { get; private set; }

        public override ModelMetadata ModelMetadata
        {
            get
            {
                var result = base.ModelMetadata;
                if (result == null)
                {
                    result = ModelMetadataProviders.Current.GetMetadataForType(() => this.Model, this.ModelDeclaringType);
                    base.ModelMetadata = result;
                }
                return result;
            }
            set
            {
                base.ModelMetadata = value;
            }
        }
        public WidgetModelMetadata WidgetModelMetadata { get { return (WidgetModelMetadata)this.ModelMetadata; } }
    }


    public class WidgetDataDictionary<TModel> : WidgetDataDictionary
    {


        public WidgetDataDictionary(ViewDataDictionary<TModel> viewData)
            : this(viewData.Model, viewData)
        {
        }
        public WidgetDataDictionary(TModel model, ViewDataDictionary viewData)
    : base(model, viewData, typeof(TModel))
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="viewData">viewData中的Model将不会被使用</param>
        /// <param name="properties"></param>
        public WidgetDataDictionary(TModel model, ViewDataDictionary viewData, WidgetModelMetadata metadata)
            : base(model, viewData, metadata)
        {
        }
    }
}

